home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2005 October / PCWOCT05.iso / Software / FromTheMag / XAMPP 1.4.14 / xampp-win32-1.4.14-installer.exe / xampp / php / pear / DB / ado.php < prev    next >
PHP Script  |  2004-03-24  |  42KB  |  1,448 lines

  1. <?php
  2. //
  3. // +----------------------------------------------------------------------+
  4. // | PHP Version 4                                                        |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2003 The PHP Group                                |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 2.02 of the PHP license,      |
  9. // | that is bundled with this package in the file LICENSE, and is        |
  10. // | available at through the world-wide-web at                           |
  11. // | http://www.php.net/license/2_02.txt.                                 |
  12. // | If you did not receive a copy of the PHP license and are unable to   |
  13. // | obtain it through the world-wide-web, please send a note to          |
  14. // | license@php.net so we can mail you a copy immediately.               |
  15. // +----------------------------------------------------------------------+
  16. // | Author: Alexios Fakos (alexios@php.net)                              |
  17. // +----------------------------------------------------------------------+
  18. //
  19. // $Id: ado.php,v 1.3 2003/01/04 11:54:52 mj Exp $
  20. //
  21.  
  22. //
  23. // Example:
  24. //
  25. //  $dsn = array(
  26. //      "phptype"  => "ado",
  27. //      "dbsyntax" => "access",  //  "mssql" or "odbc"
  28. //      "username" => "Admin",
  29. //      "password" => "",
  30. //      "database" => "Provider=Microsoft.Jet.OLEDB.4.0;
  31. //                     Data Source=C:\\Programs\\Microsoft Office\\Office\\Samples\\Nordwind.mdb;
  32. //                     Persist Security Info=False"
  33. //  );
  34. //
  35. //    $conn = DB::connect($dsn);
  36. //
  37. //  ....
  38.  
  39.  
  40.  
  41. /**
  42.  * Database independent query interface definition for Microsoft's ADODB
  43.  * library using PHP's COM extension
  44.  *
  45.  * @author   Alexios Fakos <alexios@php.net>
  46.  * @version  $Revision: 1.3 $
  47.  * @package  DB_ado
  48.  */
  49.  
  50.  
  51.  
  52. include_once(dirname(__FILE__) . '/ado_constants.php');
  53.  
  54. require_once ('DB/common.php');
  55.  
  56. class DB_ado extends DB_common
  57. {
  58.     /**
  59.      * Points on ADODB.Connection
  60.      * 
  61.      * @var     object ADODB.Connection (COM)
  62.      * @see     connect(), simpleQuery(), disconnect()
  63.      */          
  64.     var $connection;
  65.  
  66.     /**
  67.      * Database backend used in PHP (mysql, odbc etc.)
  68.      * 
  69.      * @var     string
  70.      * @see     connect(), toString()
  71.      */               
  72.     var $phptype;
  73.  
  74.     /**
  75.      * Database used with regards to SQL syntax etc.
  76.      * 
  77.      * @var     string
  78.      * @todo    defining special OLEDB-Provider (mssql, access, odbc)
  79.      * @see     connect(), createSequence(), toString()
  80.      */               
  81.     var $dbsyntax;
  82.  
  83.     /**
  84.      * Flag for method commit(), default no commit on every query
  85.      * 
  86.      * @var     boolean default true
  87.      * @see     autoCommit(), adoTrans(), commit(), rollback()
  88.      */        
  89.     var $autocommit = true;
  90.  
  91.     /**
  92.      * Flag to see how often a commit was started, Default no commit 
  93.      * on every query
  94.      * 
  95.      * @var     boolean default true
  96.      * @see     autoCommit(), simpleQuery(), rollback()
  97.      */        
  98.     var $transaction_opcount = 0;   // flag
  99.  
  100.     /**
  101.      * Result of affected rows
  102.      * 
  103.      * @var     variant
  104.      * @see     affectedRows(), simpleQuery()
  105.      */        
  106.     var $affected;
  107.  
  108.     /**
  109.      * Points on ADODB.Recordset
  110.      * 
  111.      * @var     object ADODB.Recordset (COM)
  112.      * @see     simpleQuery(), disconnect()
  113.      */    
  114.     var $recordset;
  115.  
  116.  
  117.     /**
  118.      * Specific max records to be retreived on execution.
  119.      *
  120.      * Default value 0 stays for return all records.
  121.      * 
  122.      * @var     integer default 0
  123.      * @see     setMaxRecords()
  124.      */
  125.     var $_max_records = 0;
  126.  
  127.     /**
  128.      * Specific option for ADODB.Connection and ADODB.Recordset.
  129.      *
  130.      * Valid values are:    -1 || 1 || 2 || 4 || 8 || 256 || 512
  131.      * 
  132.      * @var     integer default -1
  133.      * @see     setExecuteOption()
  134.      */
  135.     var $_execute_option = -1;
  136.  
  137.     /**
  138.      * Specific cursor location.
  139.      *
  140.      * Valid values are:    2 || 3
  141.      * 
  142.      * @var     integer  default 2
  143.      * @see     setCursorLocation()
  144.      */
  145.     var $_cursor_location = adUseClient; // 3;
  146.  
  147.     /**
  148.      * Specific cursor type.
  149.      *
  150.      * Valid values are:    -1 || 0 || 1 || 2 || 3
  151.      * 
  152.      * @var     integer default 3
  153.      * @see     setCursorType()
  154.      */
  155.     var $_cursor_type = adOpenStatic; //3;
  156.  
  157.     /**
  158.      * Specific lock type.
  159.      *
  160.      * Valid values are:    -1 || 0 || 1 || 2 || 3 || 4
  161.      * 
  162.      * @var     integer default -1
  163.      * @see     setLockType()
  164.      */
  165.     var $_lock_type = -1;
  166.  
  167. ////////////////////////////////////////////// ///////////////////////////
  168.  
  169.   
  170.   
  171.   
  172. ////////////////////////////////////////////// ///////////////////////////
  173.  
  174.     /**
  175.      * DB_ado constructor.
  176.      * Visit 
  177.      * http://support.microsoft.com/default.aspx?scid=kb;EN-US;q168354
  178.      * for $errorcode_map
  179.      * 
  180.      * @access     public
  181.      * @return     void
  182.      * @see        DB::common(), $dbsyntax, $phptype
  183.      */
  184.     function DB_ado()
  185.     {
  186.         $this->DB_common();
  187.         $this->phptype  = 'ado';
  188.         $this->dbsyntax = 'ado';
  189.         $this->features = array(
  190.                                 'prepare'       => false,
  191.                                 'pconnect'      => false,
  192.                                 'transactions'  => true,
  193.                                 'limit'         => 'alter'
  194.         );
  195.         $this->errorcode_map = array(
  196.             -2147483647  => DB_ERROR_UNSUPPORTED,
  197.             -2147467263  => DB_ERROR_UNSUPPORTED,
  198.             -2147467259  => DB_ERROR_UNSUPPORTED,
  199.             -2147217865  => DB_ERROR_NOSUCHTABLE,
  200.             -2147217900  => DB_ERROR_NOSUCHFIELD,
  201.              2147749392  => DB_ERROR_NOSUCHFIELD,
  202.             -2147217857  => DB_ERROR_ALREADY_EXISTS,
  203.             -2147217843  => DB_ERROR_CONNECT_FAILED
  204.         );
  205.         $this->affected = new VARIANT();
  206.     }
  207.  
  208.     
  209.     /**
  210.      * DB_ado destructor.
  211.      *
  212.      * @since      1.0
  213.      * @access     private
  214.      * @return     void
  215.      * @see        disconnect()
  216.      */
  217.     function _DB_ado()
  218.     {
  219.         $this->disconnect();
  220.     }
  221.  
  222.  
  223.     /**
  224.      * Connect to a database and log in as the specified user.
  225.      *
  226.      * @param      $dsn the data source name (see DB::parseDSN for syntax)
  227.      * @param      $persistent (optional) whether the connection should be 
  228.      *                         persistent (actually not supported persistent 
  229.      *                         COM objects in php)
  230.      * @access     public
  231.      * @throws     DB_Error 
  232.      * @return     mixed DB_OK on success or DB_Error on failure
  233.      * @see        adoIsError(), adoRaiseError(), raiseError()
  234.      */
  235.     function connect($dsninfo, $persistent = false)
  236.     {
  237.         if (!OS_WINDOWS) {
  238.             return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND, null, 
  239.                         null, null, 'This class runs only on Windows OS');
  240.         }
  241.  
  242.         $this->dsn = $dsninfo;
  243.         $this->dbsyntax = (string) strtolower(trim($dsninfo['dbsyntax']));
  244.         $connstr  = (string) $dsninfo['database'];
  245.         $user     = (string) $dsninfo['username'];
  246.         $pw       = (string) $dsninfo['password'];
  247.  
  248.         $this->connection = new COM("ADODB.Connection");
  249.  
  250.         if (!$this->connection) {
  251.            $errMsg  = 'Could not create an instance of ADODB.Connection.\n';
  252.            $errMsg .= 'Check if you have installed MDAC on your machine.\n';
  253.            $errMsg .= 'Take a look at '; 
  254.            $errMsg .= 'http://www.microsoft.com/data/download.htm';
  255.  
  256.            return $this->raiseError(DB_ERROR_CONNECT_FAILED, null, 
  257.                                     null, null, $errMsg);
  258.         }
  259.  
  260.         //check some valid link properties    
  261.         $link  = 'PROVIDER=|DRIVER=|DATA+SOURCE=|PERSIST+SECURITY+INFO=|UID=|';
  262.         $link .= 'USER+ID=|PASSWORD=|PWD=|INITIAL+CATALOG=';
  263.   
  264.         if (!empty($connstr) && preg_match('/\b\s*('.$link.')\b/i', $connstr)) {
  265.             @$this->connection->Open($connstr, $user, $pw);
  266.             
  267.             if (!$this->connection || $this->adoIsError()) {
  268.                 return $this->adoRaiseErrorEx(DB_ERROR_CONNECT_FAILED);
  269.             }
  270.  
  271.         } else {
  272.                 return $this->adoRaiseErrorEx(DB_ERROR_INVALID_DSN);
  273.         }
  274.  
  275.         return DB_OK;
  276.     }
  277.  
  278.  
  279.     /**
  280.      * Close ADODB.Recordset, ADODB.Connection and delete vars to free memory.
  281.      *
  282.      * @access     public
  283.      * @return     boolean always TRUE
  284.      * @see        $connection, $recordset
  285.      */
  286.     function disconnect()
  287.     {   
  288.         if (is_object($this->recordset)) {
  289.             if (@$this->recordset->State != adStateClosed) {
  290.                 @$this->recordset->Close();
  291.             }
  292.         }
  293.         if (is_object($this->connection) && 
  294.                     @$this->connection->State != adStateClosed) {
  295.             @$this->connection->Close();
  296.         }
  297.  
  298.         $this->recordset  = null;
  299.         $this->connection = null;
  300.  
  301.         return true;
  302.     }
  303.  
  304.  
  305.     /**
  306.      * Sending a query through ADODB.Connection and recieve ADO.Recordset 
  307.      * as result.
  308.      * For manip queries we use ADODB.Connection execute method instead of 
  309.      * ADO.Recordset open method.
  310.      * 
  311.      * @param      string $query sql statement 
  312.      * @access     public
  313.      * @throws     DB_Error 
  314.      * @return     mixed object ADODB.Recordset or DB_Error on failure
  315.      * @see        $connection, $recordset, $_max_records, $_cursor_type, 
  316.      *             $_lock_type, $_execute_option, $transaction_opcount, 
  317.      *             adoTrans(), commit()
  318.      */
  319.     function simpleQuery($query)
  320.     {
  321.         $ismanip = DB::isManip($query);
  322.         $this->last_query = $query;
  323.         $query = $this->modifyQuery($query);
  324.         
  325.         if (!$this->autocommit && $ismanip) {
  326.             // transaction supported?
  327.             if ($this->adoTrans()) {
  328.                 $this->transaction_opcount++;
  329.             }
  330.         }
  331.  
  332.         if ($ismanip) {
  333.  
  334.             $this->recordset = @$this->connection->Execute($query,
  335.                                                            &$this->affected,
  336.                                                            $this->_execute_option);
  337.  
  338.         } else {
  339.  
  340.             if (!is_object($this->recordset)) {
  341.                 $this->recordset = new COM('ADODB.Recordset');
  342.                 if (!$this->recordset) {
  343.                     $errMsg  = 'Creating an instance of ADODB.Recordset ';
  344.                     $errMsg .= 'failed!';
  345.                     return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND,
  346.                                                null, null, null, $errMsg);
  347.                 }
  348.             } else {
  349.                 //  close other open recordset to open a new one
  350.                 if ($this->recordset->State != adStateClosed) {  
  351.                     @$this->recordset->Close();  
  352.                 }
  353.             }
  354.  
  355.             $this->recordset->MaxRecords = $this->_max_records;
  356.             @$this->recordset->Open ($query, $this->connection, $this->_cursor_type, 
  357.                              $this->_lock_type, $this->_execute_option);
  358.         }
  359.  
  360.         if ($this->adoIsError()) {
  361.             return $this->adoRaiseErrorEx($this->errorNative());
  362.         }
  363.         
  364.         return $this->recordset;
  365.     }
  366.  
  367.  
  368.     /**
  369.      * Move the internal ADODB.Recordset result pointer to the next 
  370.      * available result.
  371.      *
  372.      * @param      object (reference) ADODB.Recordset 
  373.      * @access     public
  374.      * @return     void
  375.      */
  376.     function nextResult($result)
  377.     {
  378.         if (!@$result->EOF()) {
  379.             @$result->MoveNext();
  380.         }
  381.     }
  382.  
  383.  
  384.     /**
  385.      * Fetch and return a row of current ADODB.Recordset.
  386.      * Internally we do some important transformations for right php 
  387.      * result.
  388.      * Take a look at ADODB.DataTypeEnum for details.
  389.      *
  390.      * @param     object $result ADODB.Recordset
  391.      * @param     array $arr (reference) where data from the row is stored
  392.      * @param     integer $fetchmode how the array data should be indexed
  393.      * @param     integer $rownum the row number to fetch
  394.      * @access    public
  395.      * @return    mixed DB_OK on success, NULL on no more rows
  396.      * @todo      BINARY DATA handling
  397.      */
  398.     function fetchInto($result, &$arr, $fetchmode, $rownum=null)
  399.     {
  400.  
  401.         if ($rownum !== null && !@$result->EOF()) {
  402.             $this->pushErrorHandling(PEAR_ERROR_RETURN);
  403.             // adBookmarkFirst, start at the first record
  404.             @$result->Move($rownum, 1);
  405.             $this->popErrorHandling();
  406.             if ($this->adoIsError()) {
  407.                 return $this->adoRaiseErrorEx();
  408.             } 
  409.         }
  410.  
  411.         if (@$result->EOF()) {
  412.             return null;
  413.         }
  414.  
  415.         $arr = array();
  416.  
  417.         $count = $this->numCols($result);
  418.  
  419.         for($i = 0; $i < $count; $i++) {
  420.             $field = $result->Fields($i);
  421.             $type  = $field->Type;
  422.  
  423.             $fvalue = $field->Value;
  424.  
  425.             // avoiding 1970-01-01 01:00:00 on date values if 
  426.             // $fvalue is null or < 0
  427.             $value = null;
  428.  
  429.             if ($fvalue !== null) {
  430.                 //  adCurrency == 6
  431.                 if ($this->isTypeOfCurrency($type)) {
  432.                     $value = (float) $fvalue;
  433.                 //  adDate == 7 + adDBDate DBTYPE_DBDATE == 133
  434.                 } elseif ($this->isTypeOfDate($type)) {
  435.                     if ($fvalue > 0) {
  436.                         $value = date('Y-m-d', (integer) $fvalue);
  437.                     }
  438.                 //  adDBTime DBTYPE_DBTIME == 134
  439.                 } elseif ($this->isTypeOfTime($type)) {
  440.                     if ($fvalue > 0) {
  441.                         $value = date('H:i:s', (integer) $fvalue);
  442.                     }
  443.                 //  adDBTimeStamp DBTYPE_DBTIMESTAMP == 135
  444.                 } elseif ($this->isTypeOfTimestamp($type)) {
  445.                     if ($fvalue > 0) {
  446.                         $value = date('Y-m-d H:i:s', (integer) $fvalue);
  447.                     }
  448.                 } elseif ($this->isTypeOfBinary($type)) {
  449.                     if (is_array($fvalue)) {
  450.                         $value = ''; 
  451.                         foreach ($fvalue as $value) {
  452.                             $value .= pack('C', $value);
  453.                         } 
  454.                         $fvalue = null;
  455.                     } else {
  456.                         $value = $fvalue;
  457.                     }
  458.                 } else {
  459.                     $value = $fvalue;
  460.                 }
  461.             }
  462.  
  463.             if ($fetchmode !== DB_FETCHMODE_ASSOC) {
  464.                 $arr[] = $value;
  465.             } else {
  466.                 $arr[$field->Name] = $value;
  467.             }
  468.         }
  469.         @$result->MoveNext();
  470.  
  471.         $field = null;
  472.         unset($field);
  473.  
  474.         return DB_OK;
  475.     }
  476.  
  477.  
  478.     /**
  479.      * Get the number of columns in a recordset.
  480.      *
  481.      * @since      1.0
  482.      * @param      object $result ADODB.Recordset
  483.      * @access     public
  484.      * @return     integer the number of columns per row in $result
  485.      */
  486.     function numCols($result)
  487.     {
  488.         $cols = -1;
  489.         if (is_object($result)) {
  490.             $cols = @$result->Fields->Count();
  491.         }
  492.         return  ($cols !== -1) ? $cols : 0;
  493.     }
  494.  
  495.  
  496.     /**
  497.      * Get the number of rows in a ADODB.Recordset.
  498.      * Note: If cursor type supports does not support RecordCount, 
  499.      *       the result is always adUnknown = -1.
  500.      *
  501.      * @since      1.0
  502.      * @param      object $result ADODB.Recordset
  503.      * @access     public
  504.      * @return     integer number of rows in ADODB.Recordset
  505.      * @see        setCursorType()
  506.      */
  507.     function numRows($result)
  508.     {   
  509.         $count = -1;
  510.         if (is_object($result)) {
  511.             $count = @$result->RecordCount();
  512.         }
  513.         return  ($count !== -1) ? $count : 0;
  514.     }
  515.  
  516.  
  517.     /**
  518.      * Gets the number of rows affected by the last manip query.
  519.      *
  520.      * @since      1.0
  521.      * @access     public
  522.      * @return     integer  number of rows affected by the last query
  523.      * @see        $affected
  524.      */
  525.     function affectedRows()
  526.     {
  527.         return $this->affected->value;
  528.     }
  529.  
  530.  
  531.     /**
  532.      * Get the next value in a sequence.  Depends on $dbsyntax which type 
  533.      * we use
  534.      *
  535.      * @access     public
  536.      * @param      $seq_name the name of the sequence
  537.      * @param      $ondemand whether to create the sequence table on 
  538.      *                       demand (default is true)
  539.      * @return     mixed a sequence integer or DB_Error
  540.      */
  541.     function nextId($seq_name, $ondemand = true)
  542.     {
  543.         $sqn = preg_replace('/[^a-z0-9_]/i', '_', $seq_name);
  544.  
  545.         $repeat = 0;
  546.         do {
  547.             $this->pushErrorHandling(PEAR_ERROR_RETURN);
  548.             $rs = $this->query("UPDATE ${sqn}_seq SET id = id + 1");
  549.             $this->popErrorHandling();    
  550.  
  551.             if ($ondemand && DB::isError($rs) && 
  552.               $this->errorCode($rs->getCode()) == DB_ERROR_NOSUCHTABLE) {
  553.                 $repeat = 1;
  554.                 $rs = $this->createSequence($seq_name);
  555.             } else {
  556.                 $rs = $this->getOne("SELECT MAX(id) FROM ${sqn}_seq");
  557.                 $repeat = 0;
  558.             }
  559.         } while ($repeat);
  560.  
  561.         if (DB::isError($rs)) {
  562.             return $this->raiseError($result);
  563.         }
  564.  
  565.         return $rs;
  566.     }
  567.  
  568.     // }}}
  569.     // {{{ createSequence()
  570.  
  571.     function createSequence($seq_name)
  572.     {   
  573.         $sqn = preg_replace('/[^a-z0-9_]/i', '_', $seq_name);
  574.         
  575.         if ($this->_tableExists("${sqn}_seq")) {
  576.             return DB_OK;
  577.         }
  578.  
  579.         $ftype = $this->_helpCreateSequence();
  580.         $rs = $this->query("CREATE TABLE ${sqn}_seq " . $ftype);
  581.  
  582.         if (DB::isError($rs)) {
  583.             return $rs;
  584.         }
  585.         $rs = $this->query("INSERT INTO ${sqn}_seq (id) VALUES(0)");
  586.  
  587.         return $rs;
  588.     }
  589.  
  590.     // }}}
  591.     // {{{ dropSequence()
  592.  
  593.     function dropSequence($seq_name)
  594.     {
  595.         $sqn = preg_replace('/[^a-z0-9_]/i', '_', $seq_name);
  596.         // close recordset first to avoid table is locked
  597.         if (@$this->recordset->State != 0) {
  598.             @$this->recordset->Close();
  599.         }
  600.  
  601.         return $this->query("DROP TABLE ${sqn}_seq");
  602.     }
  603.  
  604.  
  605.     /**
  606.      * Free the internal resources associated with $result 
  607.      * (basicly it means close recordset)
  608.      *
  609.      * @since     1.0
  610.      * @param     object $result ADODB.Recordset
  611.      * @return    boolean always TRUE
  612.      */
  613.     function freeResult($result)
  614.     {
  615.         if (@$result->State != 0) {
  616.             @$result->Close();
  617.         }
  618.  
  619.         $this->affected->value     = 0;
  620.         $this->transaction_opcount = 0;
  621.  
  622.         return true;
  623.     }
  624.  
  625.     /**
  626.     * Enable automatic commit.
  627.     *
  628.     * @param      boolean $onoff (optional) default false
  629.     * @return     boolean always TRUE
  630.     * @access     public
  631.     * @see        $autocommit
  632.     */
  633.     function autoCommit($onoff = false)
  634.     {
  635.         $this->autocommit = $onoff ? true : false;
  636.         return DB_OK;
  637.     }
  638.  
  639.  
  640.     /**
  641.     * Checking of transaction support by OLEDB-Provider.
  642.     * Normally the startpoint of an transaction will be set here
  643.     *
  644.     * @param      boolean $onoff
  645.     * @return     mixed TRUE on success, FALSE if transaction is not 
  646.     *                   supported
  647.     * @throws     DB_Error
  648.     * @access     public
  649.     * @see        $autocommit, $transaction_opcount 
  650.     */
  651.     function adoTrans()
  652.     {
  653.         $ret = $this->connection->Properties('Transaction DDL');
  654.  
  655.         if (!$ret) {
  656.             return false;
  657.         } else {
  658.             $ret = null;
  659.             unset($ret);
  660.             if ($this->transaction_opcount == 0) {
  661.                 @$this->connection->BeginTrans();
  662.  
  663.                 if ($this->adoIsError()) {
  664.                     return $this->adoRaiseErrorEx();
  665.                 }
  666.             }
  667.         }
  668.  
  669.         return DB_OK;
  670.     }
  671.  
  672.  
  673.     /**
  674.     * Starts a commit
  675.     *
  676.     * @param      none
  677.     * @return     boolean TRUE on success
  678.     * @throws     DB_Error
  679.     * @access     public
  680.     * @see        $autoCommit()
  681.     */
  682.     function commit()
  683.     {
  684.         if ($this->transaction_opcount > 0) {
  685.             @$this->connection->CommitTrans(); 
  686.             
  687.             if ($this->adoIsError()) {
  688.                 return $this->adoRaiseErrorEx();
  689.             }        
  690.             $this->transaction_opcount = 0;
  691.         }
  692.  
  693.         return DB_OK;
  694.     }
  695.  
  696.  
  697.     /**
  698.     * Starts a rollback
  699.     *
  700.     * @param      none
  701.     * @return     boolean TRUE on success
  702.     * @throws     DB_Error
  703.     * @access     public
  704.     * @see        $autoCommit()
  705.     */
  706.     function rollback()
  707.     {
  708.         if ($this->transaction_opcount > 0) {
  709.             @$this->connection->RollbackTrans(); 
  710.             
  711.             if ($this->adoIsError()) {
  712.                 return $this->adoRaiseErrorEx();
  713.             }
  714.             $this->transaction_opcount = 0;
  715.         }
  716.  
  717.         return DB_OK;
  718.     }
  719.  
  720.  
  721.     /**
  722.      * Get the extended error collection of the current ADODB.Connection
  723.      *
  724.      * @since      1.0
  725.      * @access     public
  726.      * @return     string ADODB.Error
  727.      */
  728.     function errorNativeEx()
  729.     {
  730.         $errors = $this->connection->Errors();
  731.         if ($errors->Count() == 0) {
  732.             return DB_ERROR_NOT_CAPABLE;
  733.         }
  734.         
  735.         $count = $errors->Count();
  736.         $ret = '';
  737.         for($i = 0; $i < $count; $i++) {
  738.             $item = $errors->Item($i);
  739.  
  740.             $msg    = $item->Description;
  741.             $native = $item->NativeError;
  742.             $nr     = $item->Number;
  743.             $source = $item->Source; 
  744.             $sql    = $item->SQLState; 
  745.             
  746.             $ret .= "Source: $source - Description: $msg - SQLState: ";
  747.             $ret .= "$sql - Number: $nr - Native: $native \n";
  748.         }
  749.  
  750.         $item = null;
  751.         unset($item);
  752.         $errors = null;
  753.         unset($errors);
  754.  
  755.         return  $ret;
  756.     }
  757.  
  758.     
  759.     /**
  760.      * Get the native error code of the last error (if any) that
  761.      * occured on the current ADODB.Connection
  762.      *
  763.      * @since      1.0
  764.      * @access     public
  765.      * @return     string ADODB.Error
  766.      */
  767.     function errorNative()
  768.     {
  769.         $errors = $this->connection->Errors();
  770.         if ($errors->Count() == 0) {
  771.             return DB_ERROR_NOT_CAPABLE;
  772.         }
  773.  
  774.         $item = $errors->Item(0);
  775.         $ret  = (int) $item->Number;
  776.  
  777.         $item = null;
  778.         unset($item);
  779.         $errors = null;
  780.         unset($errors);
  781.  
  782.         return $ret;
  783.     }
  784.  
  785.  
  786.     /**
  787.      * Raise an error and set as param nativecode on raiseError() 
  788.      * result-string of errorNative()
  789.      *
  790.      * @param      integer $errno (optional) default null
  791.      * @since      1.0
  792.      * @access     public
  793.      * @return     void
  794.      * @see        errorNative(), raiseError()
  795.      */
  796.     function adoRaiseError($errno = null)
  797.     {
  798.         return $this->raiseError($errno, null, null, null,
  799.                                     $this->errorNative());
  800.     }
  801.  
  802.  
  803.     /**
  804.      * Raise an error and set as param nativecode on raiseError() 
  805.      * result-string of errorNative()
  806.      *
  807.      * @param      integer $errno (optional) default null
  808.      * @since      1.0
  809.      * @access     public
  810.      * @return     void
  811.      * @see        errorNativeEx(), raiseError()
  812.      */
  813.     function adoRaiseErrorEx($errno = null)
  814.     {
  815.         if ($errno === null) {
  816.             $errno = $this->errorCode($errno);
  817.         }
  818.         return $this->raiseError($errno, null, null, null,
  819.                                     $this->errorNativeEx());
  820.     }
  821.  
  822.     
  823.     /**
  824.      * Checking if an ADODB.Connection error occured
  825.      *
  826.      * @param      none
  827.      * @since      1.0
  828.      * @access     public
  829.      * @return     boolean TRUE error(s) occured, 
  830.      *                     FALSE no error occured
  831.      */
  832.     function adoIsError()
  833.     {   
  834.         if ($this->connection->Errors->Count() > 0 &&
  835.                             is_object($this->connection)) {
  836.             return true;
  837.         }
  838.         return false;
  839.     }
  840.   
  841.  
  842.     /**
  843.      * Set execute option for ADODB.Connection. Only for manip queries.
  844.      *
  845.      * CommandTypeEnum
  846.      *      adCmdText        = 1
  847.      *      adCmdTable       = 2
  848.      *      adCmdStoredProc  = 4
  849.      *      adCmdUnknown     = 8
  850.      *      adCmdFile        = 256
  851.      *      adCmdTableDirect = 512
  852.      *
  853.      * @param      integer $value (optional) default -1
  854.      * @since      1.0
  855.      * @access     public
  856.      * @return     boolean TRUE we set the $value, FALSE wrong Enum was 
  857.      *                     given
  858.      * @see        $_execute_option
  859.      */
  860.     function setExecuteOption($value = -1)
  861.     {    
  862.         if ($value > 0 && $value < 3) {
  863.         } elseif ($value == -1) {
  864.         } elseif ($value == 4) {
  865.         } elseif ($value == 8) {
  866.         } elseif ($value == 256) {
  867.         } elseif ($value == 512) {
  868.         } else {
  869.             return false;
  870.         }
  871.         $this->_execute_option = $value;
  872.  
  873.         return true;
  874.     }
  875.  
  876.  
  877.     /**
  878.      * Set the cursor type for ADODB.Recordset. 
  879.      * Only for catching records.
  880.      *
  881.      * Notes: 
  882.      * Use adOpenKeyset = 1 or adOpenstatic = 3 to get a 
  883.      * value > 0 of numRows().
  884.      *
  885.      * CursorTypeEnum
  886.      *      adOpenUnspecified   = -1
  887.      *      adOpenForwardOnly   = 0
  888.      *      adOpenKeyset        = 1
  889.      *      adOpenDynamic       = 2   
  890.      *      adOpenStatic        = 3  
  891.      *
  892.      * @param      integer $value (optional) default -1
  893.      * @since      1.0
  894.      * @access     public
  895.      * @return     boolean TRUE we set the $value, 
  896.      *                     FALSE wrong Enum was given
  897.      * @see        numRows(), $_cursor_type
  898.      */
  899.     function setCursorType($value = -1)
  900.     {   
  901.         if ($value >= 0 || $value < 4) {
  902.             $this->_cursor_type = $value;
  903.             return true;
  904.         }
  905.         return false;
  906.     }
  907.  
  908.     
  909.     /**
  910.      * Set the cursor location for ADODB.Connection
  911.      *
  912.      * CursorLocationEnum
  913.      *      adUseServer     = 2
  914.      *      adUseClient     = 3
  915.      *
  916.      * @param      integer $value (optional) default 3
  917.      * @since      1.0
  918.      * @access     public
  919.      * @return     boolean TRUE we set the $value, 
  920.      *                     FALSE wrong Enum was given
  921.      * @see        $_cursor_location
  922.      */
  923.     function setCursorLocation($value = 3)
  924.     {
  925.         if ($value > 1 && $value < 4) {
  926.             $this->_cursor_location = $value;
  927.             return true;
  928.         }
  929.         return false;
  930.     }
  931.  
  932.  
  933.     /**
  934.      * Set the lock type for ADODB.Recordset. Only for catching records.
  935.      *
  936.      * LockTypeEnum
  937.      *      adLockUnspecified       = -1
  938.      *      adLockReadOnly          = 1
  939.      *      adLockPessimistic       = 2   
  940.      *      adLockOptimistic        = 3  
  941.      *      adLockBatchOptimistic   = 4
  942.      *
  943.      * @param      integer $value (optional) default -1
  944.      * @since      1.0
  945.      * @access     public
  946.      * @return     boolean TRUE we set the $value, 
  947.      *                     FALSE wrong Enum was given
  948.      * @see        $_lock_type
  949.      */
  950.     function setLockType($value = -1)
  951.     {
  952.         if ($value > 0 || $value < 5) {
  953.             $this->_lock_type = $value;
  954.             return true;
  955.         }
  956.         return false;
  957.     }
  958.  
  959.  
  960.    /**
  961.     * Setting of MaxRecords to get only xx records on every query
  962.     *
  963.     * Note: msdn-article (Q186267)
  964.     * "PRB: MaxRecords Property Is Not Used in Access Queries with ADO"
  965.     *
  966.     * @param      integer $value (optional) default 0
  967.     * @since      1.0
  968.     * @access     public
  969.     * @return     boolean TRUE we set the $value, 
  970.     *                     FALSE no integer value was given
  971.     * @see        $_max_records
  972.     */
  973.     function setMaxRecords($value = 0)
  974.     {
  975.         if (is_int($value)) {
  976.             $this->_max_records = $value;
  977.             return true;
  978.         }
  979.         return false;
  980.     }
  981.  
  982.  
  983.     
  984.     /**
  985.      * Help function to get string of field declaration
  986.      *
  987.      * @return     string fieldtype and conditions
  988.      * @see        createSequence()
  989.      */
  990.     function _helpCreateSequence()
  991.     {
  992.         $dbsyntax = strtolower($this->dbsyntax);
  993.  
  994.         if ($dbsyntax == 'access') {
  995.             $ftype = '(id LONG NOT NULL, PRIMARY KEY(id))';
  996.         } else {
  997.             // odbc compliant
  998.             $ftype = '(id BIGINT NOT NULL, PRIMARY KEY(id))';
  999.         }
  1000.  
  1001.         return $ftype;
  1002.     }
  1003.  
  1004.  
  1005.  
  1006.     /**
  1007.      * Help function to know if table exists
  1008.      *
  1009.      * param       string $value tablename
  1010.      * @return     boolean TRUE table exists, FALSE table does not exist
  1011.      * @see        createSequence()
  1012.      */
  1013.     function _tableExists($value)
  1014.     {
  1015.         $ok = false;
  1016.         $cat = new COM('ADOX.Catalog');
  1017.  
  1018.         if ($cat) {
  1019.  
  1020.         // @$cat->ActiveConnection = $this->connection;
  1021.         // can use it in this way, i get always a seq fault of php.exe, 
  1022.         // maybe a bug reported bug-id #16720
  1023.         // so we use an alternative way ...
  1024.  
  1025.             @$cat->ActiveConnection = $this->connection->ConnectionString;
  1026.  
  1027.             $tables = @$cat->Tables;
  1028.             $count = $tables->Count();
  1029.             
  1030.             for($i = 0; $i < $count; $i++) {
  1031.                 $table = $tables->Item($i);
  1032.                 if (strtolower($table->Type) != 'view' &&
  1033.                         strtolower($table->Name) == $value) {
  1034.                     $ok = true;
  1035.                     break;
  1036.                 }
  1037.             }
  1038.             $table = null; 
  1039.             unset($table);
  1040.             $tables = null; 
  1041.             unset($tables);
  1042.             $cat = null;
  1043.             unset($cat);
  1044.         }
  1045.  
  1046.         return $ok;
  1047.     }
  1048.  
  1049.  
  1050.    // }}}
  1051.    // {{{ tableInfo()
  1052.  
  1053.     function tableInfo($result, $mode = null) {
  1054.         $count = 0;
  1055.         $id    = 0;
  1056.         $res   = array();
  1057.  
  1058.         // if $result is a string, then we want information about a
  1059.         // table without a resultset
  1060.         if (is_string($result)) {
  1061.             $table_name = $result;
  1062.         } else { // is_object
  1063.             $sql = $this->last_query;
  1064.             $table_name = strtolower($this->_getTableNameFromSQL($sql));
  1065.             // or @$result->Source
  1066.             if (empty($table_name)) {
  1067.                 return $this->raiseError(DB_ERROR_INVALID, null, null,
  1068.                         null, 'Empty table name in tableInfo() ' . __LINE__);
  1069.             }
  1070.         }
  1071.  
  1072.         $cat = new COM('ADOX.Catalog');
  1073.  
  1074.         if ($cat) {
  1075.  
  1076.             @$cat->ActiveConnection = $this->connection->ConnectionString;
  1077.  
  1078.             $tables = @$cat->Tables;
  1079.             $count = $tables->Count();
  1080.  
  1081.             if (!empty($mode)) {
  1082.                 $res['num_fields']= $count;
  1083.             }
  1084.             for($i = 0; $i < $count; $i++) {
  1085.                 $table = $tables->Item($i);
  1086.                 if (strtolower($table->Type) != 'view' &&
  1087.                         strtolower($table->Name) == $table_name) {
  1088.                     
  1089.                     for($x = 0; $x < $table->Columns->Count(); $x++) {
  1090.                         $column = $table->Columns->Item($x);
  1091.                         $res[$x]['table']= (string) @$table->Name;
  1092.                         $res[$x]['name'] = (string) @$column->Name;
  1093.                         $type = $this->_getStringOfADOType($column->Type);
  1094.                         $res[$x]['type'] = (string) $type;
  1095.                         $res[$x]['len']  = (string) @$column->DefinedSize;
  1096.                         $flags = $this->_getFlags4TableInfo($column);
  1097.                         $res[$x]['flags']= (string) $flags;
  1098.  
  1099.                         if (!empty($mode)) {
  1100.                             if ($mode & DB_TABLEINFO_ORDER) {
  1101.                                 $res['order'][$res[$x]['name']] = $x;
  1102.                             }
  1103.                             if ($mode & DB_TABLEINFO_ORDERTABLE) {
  1104.                                 $res['ordertable'][$res[$x]['table']][$res[$x]['name']] = $x;
  1105.                             }                        
  1106.                         }
  1107.                     }
  1108.                     break;
  1109.                 } // $table_name
  1110.             }
  1111.         } // !$cat
  1112.  
  1113.         $column = null;
  1114.         unset($column);
  1115.         $table = null;
  1116.         unset($table);
  1117.         $tables = null;
  1118.         unset($tables);
  1119.         $cat = null;
  1120.         unset($cat);
  1121.  
  1122.         return $res;
  1123.     }
  1124.  
  1125. // todo: transforming ret int-value to string
  1126.     /**
  1127.      * Get MS ADODB integer value of field type
  1128.      * as human string 
  1129.      *
  1130.      * @param      string $value integer value of ADODB field type
  1131.      * @access     privat
  1132.      * @return     string human string
  1133.      */
  1134.     function _getStringOfADOType($value)
  1135.     {   
  1136.         $ret = 'char';
  1137.  
  1138.         if ($this->isTypeOfBinary($value)) {
  1139.             $ret = 'binary';
  1140.         } elseif ($this->isTypeOfBit($value)) {
  1141.             $ret = 'bit';
  1142.         } elseif ($this->isTypeOfDecimal($value)) {
  1143.             $ret = 'decimal';
  1144.         } elseif ($this->isTypeOfNumeric($value)) {
  1145.             $ret = 'numeric';
  1146.         } elseif ($this->isTypeOfDouble($value)) {
  1147.             $ret = 'double';
  1148.         } elseif ($this->isTypeOfFloat($value)) {
  1149.             $ret = 'float';
  1150.         } elseif ($this->isTypeOfReal($value)) {
  1151.             $ret = 'real';
  1152.         } elseif ($this->isTypeOfCurrency($value)) {
  1153.             $ret = 'currency';
  1154.         } elseif ($this->isTypeOfInteger($value)) {
  1155.             $ret = 'int';
  1156.         } elseif ($this->isTypeOfTime($value)) {
  1157.             $ret = 'datetime';
  1158.         } elseif ($this->isTypeOfTimestamp($value)) {
  1159.             $ret = 'timestamp';
  1160.         } elseif ($this->isTypeOfDate($value)) {
  1161.             $ret = 'date';
  1162.         }
  1163.  
  1164.         return $ret;
  1165.     }
  1166.  
  1167.  
  1168.     /**
  1169.      * Receiving of the table name in a SQL query string
  1170.      *
  1171.      * @param      string $value SQL query string
  1172.      * @access     privat
  1173.      * @return     string table name in the SQL query
  1174.      */
  1175.     function _getTableNameFromSQL($value)
  1176.     {   
  1177.         $sql = ltrim($value);
  1178.         $from_part = stristr($sql, 'from');
  1179.         $from_array = split(' ', $from_part);
  1180.  
  1181.         return (string) $from_array[1];
  1182.     }
  1183.  
  1184.     /**
  1185.      * Transform MS ADODB Enum into php readable string
  1186.      * 
  1187.      * @param      object $column column item
  1188.      * @access     privat
  1189.      * @return     string empty string or the name type of column
  1190.      */
  1191.     function _getFlags4TableInfo($column)
  1192.     {   
  1193.         $this->pushErrorHandling(PEAR_ERROR_RETURN);
  1194.         $ret = '';
  1195.         if ($column->Properties->Count() > 0) {
  1196.             $property = @$column->Properties('Nullable');
  1197.             $ret .= (string) (@$property->Value == false) ? 'not_null' : '';
  1198.             $property = @$column->Properties('Autoincrement');
  1199.             $ret .= (string) (@$property->Value == true) ? 'auto_increment' : '';
  1200.             $property = @$column->Properties('Primary Key');
  1201.             $ret .= (string) (@$property->Value == true) ? 'primary_key' : '';
  1202.             $property = @$column->Properties('Unique');
  1203.             $ret .= (string) (@$property->Value == true) ? 'unique' : '';
  1204.         }
  1205.         $this->popErrorHandling();
  1206.  
  1207.         $property = null;
  1208.         unset($property);
  1209.  
  1210.         return $ret;
  1211.     }
  1212.  
  1213.  
  1214.  
  1215.  
  1216.     /**
  1217.      * Returns ADODB version
  1218.      *
  1219.      * @access    (public)
  1220.      * @return    string  ADODB version
  1221.      */
  1222.     function getVersion()
  1223.     {
  1224.         if (is_object($this->connection)) {
  1225.             return (string) $this->connection->Version;
  1226.         }
  1227.         return '';
  1228.     }
  1229.  
  1230.  
  1231.     /**
  1232.      * Returns ADODB Provider
  1233.      *
  1234.      * @access    (public)
  1235.      * @return    string  ADODB version
  1236.      */
  1237.     function getProvider()
  1238.     {
  1239.         if (is_object($this->connection)) {
  1240.             return (string) $this->connection->Provider;
  1241.         }
  1242.         return '';
  1243.     }
  1244.  
  1245.  
  1246.     /**
  1247.      * Checks if field is a binary type
  1248.      *
  1249.      * @param      integer $value fieldtype
  1250.      * @access     public
  1251.      * @return     boolean TRUE on match, FALSE if other type
  1252.      */
  1253.     function isTypeOfBinary($value)
  1254.     {
  1255.         if ($value == adBinary || $value == adVarBinary ||
  1256.                 $value == adLongVarBinary) {
  1257.             return true;
  1258.         }
  1259.         return false;
  1260.     }
  1261.  
  1262.     /**
  1263.      * Checks if field is a bit type
  1264.      *
  1265.      * @param      integer $value fieldtype
  1266.      * @access     public
  1267.      * @return     boolean TRUE on match, FALSE if other type
  1268.      */
  1269.     function isTypeOfBit($value)
  1270.     {
  1271.         if ($value == adBoolean) {
  1272.             return true;
  1273.         }
  1274.         return false;
  1275.     }
  1276.  
  1277.  
  1278.     /**
  1279.      * Checks if field is a char type
  1280.      *
  1281.      * @param      integer $value fieldtype
  1282.      * @access     public
  1283.      * @return     boolean TRUE on match, FALSE if other type
  1284.      */
  1285.     function isTypeOfChar($value)
  1286.     {
  1287.         if ($value == adChar || $value == adVarChar || 
  1288.                 $value == adWChar || $value == adVarWChar ||
  1289.                 $value == adLongVarChar || $value == adLongVarWChar) {
  1290.             return true;
  1291.         }
  1292.         return false;
  1293.     }
  1294.  
  1295.  
  1296.     /**
  1297.      * Checks if field is a date type
  1298.      *
  1299.      * @param      integer $value fieldtype
  1300.      * @access     public
  1301.      * @return     boolean TRUE on match, FALSE if other type
  1302.      */
  1303.     function isTypeOfDate($value)
  1304.     {
  1305.         if ($value == adDate || $value == adDBDate) {
  1306.             return true;
  1307.         }
  1308.         return false;
  1309.     }
  1310.  
  1311.     /**
  1312.      * Checks if field is a decimal type
  1313.      *
  1314.      * @param      integer $value fieldtype
  1315.      * @access     public
  1316.      * @return     boolean TRUE on match, FALSE if other type
  1317.      */
  1318.     function isTypeOfDecimal($value)
  1319.     {
  1320.         if ($value == adNumeric) {
  1321.             return true;
  1322.         }
  1323.         return false;
  1324.     }
  1325.  
  1326.     /**
  1327.      * Checks if field is a numeric type
  1328.      *
  1329.      * @param      integer $value fieldtype
  1330.      * @access     public
  1331.      * @return     boolean TRUE on match, FALSE if other type
  1332.      */
  1333.     function isTypeOfNumeric($value)
  1334.     {
  1335.         if ($value == adNumeric) {
  1336.             return true;
  1337.         }
  1338.         return false;
  1339.     }
  1340.  
  1341.     /**
  1342.      * Checks if field is a double type
  1343.      *
  1344.      * @param      integer $value fieldtype
  1345.      * @access     public
  1346.      * @return     boolean TRUE on match, FALSE if other type
  1347.      */
  1348.     function isTypeOfDouble($value)
  1349.     {
  1350.         if ($value == adDouble) {
  1351.             return true;
  1352.         }
  1353.         return false;
  1354.     }
  1355.  
  1356.     /**
  1357.      * Checks if field is a float type
  1358.      *
  1359.      * @param      integer $value fieldtype
  1360.      * @access     public
  1361.      * @return     boolean TRUE on match, FALSE if other type
  1362.      */
  1363.     function isTypeOfFloat($value)
  1364.     {
  1365.         if ($value == adSingle) {
  1366.             return true;
  1367.         }
  1368.         return false;
  1369.     }
  1370.  
  1371.     /**
  1372.      * Checks if field is a real type
  1373.      *
  1374.      * @param      integer $value fieldtype
  1375.      * @access     public
  1376.      * @return     boolean TRUE on match, FALSE if other type
  1377.      */
  1378.     function isTypeOfReal($value)
  1379.     {
  1380.         if ($value == adSingle) {
  1381.             return true;
  1382.         }
  1383.         return false;
  1384.     }
  1385.  
  1386.     /**
  1387.      * Checks if field is a integer type
  1388.      *
  1389.      * @param      integer $value fieldtype
  1390.      * @access     public
  1391.      * @return     boolean TRUE on match, FALSE if other type
  1392.      */
  1393.     function isTypeOfInteger($value)
  1394.     {
  1395.         if ($value == adInteger || $value == adSmallInt ||
  1396.                 $value == adUnsignedTinyInt) {
  1397.             return true;
  1398.         }
  1399.         return false;
  1400.     }
  1401.  
  1402.     /**
  1403.      * Checks if field is a currency type
  1404.      * (which is not supported by php)
  1405.      *
  1406.      * @param      integer $value fieldtype
  1407.      * @access     public
  1408.      * @return     boolean TRUE on match, FALSE if other type
  1409.      */
  1410.     function isTypeOfCurrency($value)
  1411.     {
  1412.         if ($value == adCurrency) {
  1413.             return true;
  1414.         }
  1415.         return false;
  1416.     }
  1417.  
  1418.     /**
  1419.      * Checks if field is a time type
  1420.      *
  1421.      * @param      integer $value fieldtype
  1422.      * @access     public
  1423.      * @return     boolean TRUE on match, FALSE if other type
  1424.      */
  1425.     function isTypeOfTime($value)
  1426.     {
  1427.         if ($value == adDBTime) {
  1428.             return true;
  1429.         }
  1430.         return false;
  1431.     }
  1432.  
  1433.     /**
  1434.      * Checks if field is a timestamp type
  1435.      *
  1436.      * @param      integer $value fieldtype
  1437.      * @access     public
  1438.      * @return     boolean TRUE on match, FALSE if other type
  1439.      */
  1440.     function isTypeOfTimestamp($value)
  1441.     {
  1442.         if ($value == adDBTimeStamp) {
  1443.             return true;
  1444.         }
  1445.         return false;
  1446.     }
  1447.  
  1448. }  // class DB_ado